#include <fstream>
#include <iostream>
#include <cassert>
#include <Geometry/smesh.h>
#include <string.h>
#include <Geometry/Loader/tiny_obj_loader.h>
using std::fstream;
using std::string;
using std::vector;
using std::cout;
using std::endl;

namespace PhysLeo{

void Smesh::loadFromObj(const string& filename)
{
	//read obj file
	tinyobj::attrib_t attrib;
	vector<tinyobj::shape_t> shapes;
	vector<tinyobj::material_t> materials;

	string err;
	auto ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str());// default do trianglization

	if (!err.empty()) {
		cout << err << endl;
	}
	assert(ret);
    ele_type_ = EleType::TRI;
    vertex_num_ = static_cast<int>(attrib.vertices.size() / 3);
    pos_.resize(vertex_num_);
    memcpy(pos_.data(), attrib.vertices.data(), vertex_num_ * sizeof(glm::tvec3<float>));

	for (auto& shape : shapes)
	{
		const auto lenth = static_cast<int>(shape.mesh.indices.size());
		for (auto j = 0; j < lenth; ++j)
		{
			ele_.push_back(shape.mesh.indices[j].vertex_index);
		}
	}
}

void Smesh::loadFromAbq(fstream &file)
{
	string markline;
	char linebuff[1000];
	char comma;
	while (file >> markline)
	{
		if (markline.substr(0, 2) == "**")
		{
			//comment
			file.getline(linebuff, 1000);
			//print comment
			cout << linebuff << endl;
		}
		else if (markline == "*NODE")
		{
			cout << markline << endl;

			int pos_index;
			float x, y, z;
			while (file >> pos_index)
			{
				file >> comma >> x >> comma >> y >> comma >> z;
                pos_.push_back(glm::tvec3<float>(x,y,z));
			}
			file.clear();
		}
		else if (markline.substr(0, 8) == "*ELEMENT")
		{
			cout << markline << endl;

			file.getline(linebuff, 1000);
			markline += linebuff;
			markline = markline.substr(markline.find_first_of('='));
			const auto ele_type = markline.substr(1);

			cout << "element type: " << ele_type << endl;
			if (ele_type == string("C3D8")) ele_type_ = EleType::HEX;
			else if (ele_type == string("C3D4")) ele_type_ = EleType::TET;
			else
			{
				cout << "unknow element type error!" << endl;
				return;
			}

			int ele_index;
			int vert_index;
			while (file >> ele_index)
			{
				for (int i = 0; i < eleVertNum(); ++i)
				{
					file >> comma >> vert_index;
					ele_.push_back(vert_index - 1);
				}
			}
			file.clear();//清楚流的错误标志 让其能够继续读入
		}
		else
		{
			//comment
			file.getline(linebuff, 1000);
			//print comment
			cout << linebuff << endl;
		}
	}
}

void Smesh::loadFromInp(fstream &file)
{
	string markline;
	char linebuff[1000];
	char comma;
	while (file >> markline)
	{
		if (markline.substr(0, 2) == "**")
		{
			//comment
			file.getline(linebuff,1000);
			//print comment
			cout << linebuff << endl;
		}
		else if (markline == "*NODE")
		{
			cout << markline << endl;

			int pos_index;
			float x, y, z;
			while (file >> pos_index)
			{
				file >> comma >> x >> comma >> y >> comma >> z;
                pos_.push_back(glm::tvec3<float>(x, y, z));
			}
			file.clear();
		}
		else if (markline.substr(0, 8) == "*ELEMENT")
		{
			cout << markline << endl;

			file.getline(linebuff, 1000);
			markline += linebuff;
			markline = markline.substr(markline.find_first_of('='));
			const auto comma_index = static_cast<int>(markline.find_first_of(','));
			const auto ele_type = markline.substr(1, comma_index - 1);
			markline = markline.substr(comma_index);
			markline = markline.substr(markline.find_first_of('='));
			const auto region_name = markline.substr(1);

			cout << "element type: " << ele_type << " region name: " << region_name << endl;
			if (ele_type == string("C3D8R")) ele_type_ = EleType::HEX;
			else if (ele_type == string("C3D4")) ele_type_ = EleType::TET;
			else if (ele_type == string("S4R")) ele_type_ = EleType::QUAD;
			else
			{
				cout << "unknow element type error!" << endl;
				return;
			}

			int ele_index;
			int vert_index;
			while (file>>ele_index)
			{
				for (int i = 0; i < eleVertNum(); ++i)
				{
					file >> comma >> vert_index;
					ele_.push_back(vert_index - 1);
				}
			}
			file.clear();//清楚流的错误标志 让其能够继续读入
		}
		else
		{
			//comment
			file.getline(linebuff,1000);
			//print comment
			cout << linebuff << endl;
		}
	}
}

void Smesh::loadFromSmesh(fstream &file)
{
	string part_string;
	auto index_base = 1;
	while (file >> part_string) {
		if (part_string == "*VERTICES") {
			int vert_num, dimension, option1, option2;
			file >> vert_num >> dimension >> option1 >> option2;
			pos_.resize(vert_num);
			for (auto i = 0; i < vert_num; ++i) {
				int vert_index;
				file >> vert_index >> pos_[i][0] >> pos_[i][1] >> pos_[i][2];
				if (i == 0 && vert_index == 0)index_base = 0;
				assert(i + index_base == vert_index);
			}
		}
		else if (part_string == "*ELEMENTS") {
			string ele_type;
			file >> ele_type;

			if (ele_type == "HEX") ele_type_ = EleType::HEX;
			else if (ele_type == "TET") ele_type_ = EleType::TET;
			else if (ele_type == "QUAD") ele_type_ = EleType::QUAD;
			else if (ele_type == "TRI") ele_type_ = EleType::TRI;
            else
            {
                cout<<"unknow element type!"<<endl;
                return;
            }

			int ele_num, ele_vert_num, option1;
			file >> ele_num >> ele_vert_num >> option1;
			ele_.resize(ele_num*ele_vert_num);
			for (auto i = 0; i < ele_num; ++i) {
				int ele_index;
				file >> ele_index;
				assert(i + index_base == ele_index);
				for (auto j = 0; j < ele_vert_num; ++j) {
					file >> ele_[i*ele_vert_num + j];
					ele_[i*ele_vert_num + j] -= index_base;
				}
			}
		}
		else
		{
			//comment
			cout<<part_string<<" ";
		}
	}
}

void Smesh::computeVolume()
{
    ele_volume_.resize(ele_num_, 0.0f);
    vert_volume_.resize(vertex_num_, 0.0f);
    const auto ele_vert_num = eleVertNum();
    std::vector<glm::tvec3<float>> pos(ele_vert_num);
    for(auto i=0;i<ele_num_;++i)
    {
        for (auto j = 0; j < ele_vert_num; ++j)
            pos[j] = pos_[ele_[i*ele_vert_num + j]];
        ele_volume_[i] = volumeFromEleType(ele_type_, pos);
        for (auto j = 0; j < ele_vert_num; ++j)
            vert_volume_[ele_[i*ele_vert_num + j]] += ele_volume_[i] / ele_vert_num;
    }
}

}